﻿// -----------------------------------------------------------------------
// <copyright file="UnixDateTimeGenerator.cs" company="none">
// Copyright (c) 2012 M. Alberti, xanatos(at)live.it
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
// </copyright>
// -----------------------------------------------------------------------

namespace FluentSerializer.Generators
{
    using System;
    using System.Linq.Expressions;
    using System.Reflection;
    using FluentSerializer;

    /// <summary>
    /// 
    /// </summary>
    public static class UnixDateTimeGenerator
    {
        /// <summary>
        /// 
        /// </summary>
        private static readonly MethodInfo UnixTimeToDateTime = typeof(UnixDateTime).GetMethod("ToDateTime", BindingFlags.Static | BindingFlags.Public, null, new[] { typeof(long) }, null);

        /// <summary>
        /// 
        /// </summary>
        private static readonly MethodInfo DateTimeToUnixTime = typeof(UnixDateTime).GetMethod("ToUnixTime", BindingFlags.Static | BindingFlags.Public, null, new[] { typeof(DateTime) }, null);

        /// <summary>
        /// 
        /// </summary>
        /// <param name="serializer"></param>
        /// <param name="parametersType"></param>
        /// <param name="type"></param>
        /// <param name="helper"></param>
        /// <returns></returns>
        public static Descriptor BuildSerializer(Serializer serializer, Type parametersType, Type type, Type helper)
        {
            Type subType = type.GetGenericArguments()[0];

            if (!Serializer.IsConvertible(Serializer.Zero, subType))
            {
                throw new NotSupportedException();
            }

            Descriptor descriptor1 = Serializer.GetSerializer(serializer, subType, subType, helper);

            ParameterExpression item = Expression.Parameter(typeof(DateTime));
            ParameterExpression parameters = null;

            LambdaExpression deserializeExpression;
            LambdaExpression serializeExpression;
            LambdaExpression sizeExpression;

            Type standardSerializedType = typeof(long);

            /***/
            {
                Expression deserializedItem = Serializer.MakeFromLambda(descriptor1.DeserializeExpression, descriptor1.IsUniversal, Serializer.ReaderExpression, descriptor1.DefaultExpression, parameters);

                if (subType != standardSerializedType)
                {
                    deserializedItem = Expression.ConvertChecked(deserializedItem, standardSerializedType);
                }

                deserializeExpression = Serializer.MakeLambda(Expression.Call(UnixTimeToDateTime, deserializedItem), descriptor1.IsUniversal, Serializer.ReaderExpression, item, parameters);
            }

            /***/
            {
                Expression serializedItem = Expression.Call(DateTimeToUnixTime, item);

                if (subType != standardSerializedType)
                {
                    serializedItem = Expression.ConvertChecked(serializedItem, subType);
                }

                serializeExpression = Serializer.MakeLambda(Serializer.MakeFromLambda(descriptor1.SerializeExpression, descriptor1.IsUniversal, Serializer.WriterExpression, serializedItem, parameters), descriptor1.IsUniversal, Serializer.WriterExpression, item, parameters);
            }

            /***/
            {
                sizeExpression = Serializer.MakeLambda(Serializer.MakeFromLambda(descriptor1.SizeExpression, descriptor1.IsUniversal, descriptor1.DefaultExpression, parameters), descriptor1.IsUniversal, item, parameters);
            }

            var descriptor2 = new Descriptor(type, descriptor1.IsUniversal, deserializeExpression, DeserializationHandling.RequireAssignment, serializeExpression, sizeExpression);
            return descriptor2;
        }
    }
}